<?php

namespace App\Task\Stat;

use App\Model\PayOrder;
use App\Model\Stat\StatDailyKeep;
use App\Model\User;
use App\Model\UserActLog;
use App\Model\UserProfile;
use Hyperf\Crontab\Annotation\Crontab;

/**
 * 留存统计
 * @Crontab(name="StatDailyKeepTask", rule="6 6 * * *", callback="execute", memo="留存统计", singleton=true)
 */
class StatDailyKeepTask
{
    //留存天数
    protected $keepDays = [1, 2, 3, 7, 15, 30];

    public function execute()
    {
        // return $this->initRecords(45);
        log_info(__CLASS__ . "==Start==" . date('Y-m-d H:i:s'));
        $days = [
            2 => [1],
            3 => [2],
            4 => [3],
            8 => [7],
            16 => [15],
            31 => [30],
        ];
        foreach (StatDailyKeep::STAT_TYPE as $statType => $type) {
            $this->statType = $statType;
            foreach ($days as $offDay => $dayArr) {
                $dt = date('Y-m-d', strtotime("-{$offDay} day"));
                $regUserIds = $this->getOffDateRegUids($offDay, $statType);
                if (empty($regUserIds)) continue;
                $info = [];
                foreach ($dayArr as $keepDay) {
                    $keepInfo = $this->getKeep($offDay, $keepDay, $regUserIds);
                    $info["keep_{$keepDay}"] = $keepInfo['keep'];
                    $info["keep_{$keepDay}_num"] = $keepInfo['keep_num'];
                }
                StatDailyKeep::updateOrCreate(['dt' => $dt, 'stat_type' => $statType], $info);
            }
        }
    }

    /**
     * 计算offDay天前的keepDay天留存
     */
    function getKeep($offDay = 2, $keepDay = 1, $offDayRegUids = [])
    {
        if ($offDay <= $keepDay) return ['keep' => 0, 'keep_num' => 0];
        $calDate = date('Y-m-d', strtotime("-{$offDay} day"));
        $keepStart = date('Y-m-d', strtotime("-" . ($offDay - $keepDay) . " day"));
        $keepEnd = date('Y-m-d', strtotime("-" . ($offDay - $keepDay - 1) . " day"));
        $keepUserIds = UserActLog::checkActiveCount([], $keepStart, $keepEnd, '', 'uid');
        $keepUserIds = array_intersect($offDayRegUids, $keepUserIds);
        $regCount = count($offDayRegUids);
        $keepCount = count($keepUserIds);
        $keep = !$regCount ? 0 : round($keepCount / $regCount, 3) * 100;
        $type = StatDailyKeep::STAT_TYPE[$this->statType] ?? '--';
        log_info(__METHOD__ . "=={$calDate}的{$type}第{$keepDay}天留存率：{$keep}%");
        return ['keep' => $keep, 'keep_num' => $keepCount];
    }

    /**
     * 查询offDay天前的注册用户ID
     */
    function getOffDateRegUids($offDay = 1, $statType = StatDailyKeep::STAT_TYPE_ALL)
    {
        $dt = date('Y-m-d', strtotime("-{$offDay} day"));
        $dtNext = date('Y-m-d', strtotime("-" . ($offDay - 1) . " day"));
        switch ($statType) {
            case StatDailyKeep::STAT_TYPE_ALL:
                return User::getRegUsers($dt, $dtNext, 'uid');
            case StatDailyKeep::STAT_TYPE_HOST:
                return UserProfile::getRegCount(0, UserProfile::ROLE_HOST, $dt, $dtNext, '', 'uid');
            case StatDailyKeep::STAT_TYPE_USER:
                return UserProfile::getRegCount(1, UserProfile::ROLE_USER, $dt, $dtNext, '', 'uid');
            case StatDailyKeep::STAT_TYPE_RECHARGE:
                return PayOrder::getNewRechargeUsers($dt, $dtNext);
        }
        return [];
    }

    /**
     * 初始化50天的记录
     */
    protected function initRecords($day = 60)
    {
        foreach (StatDailyKeep::STAT_TYPE as $statType => $type) {
            for ($offDay = $day; $offDay > 0; $offDay--) {
                $dt = date('Y-m-d', strtotime("-{$offDay} day"));
                $this->statType = $statType;
                $regUserIds = $this->getOffDateRegUids($offDay, $statType);
                $info = [];
                foreach ($this->keepDays as $keepDay) {
                    $keepInfo = $this->getKeep($offDay, $keepDay, $regUserIds);
                    $info["keep_{$keepDay}"] = $keepInfo['keep'];
                    $info["keep_{$keepDay}_num"] = $keepInfo['keep_num'];
                }
                StatDailyKeep::updateOrCreate(['dt' => $dt, 'stat_type' => $statType], $info);
            }
        }
        return;
    }
}
